import std.stdio;
import bignum, rational;

//足し算で2**r
Bignum pow2(int r) {
  Bignum n = new Bignum(1);
  for(int i=0; i<r; i++) {
    n=bigadd(n,n);
  }
  return n;
}

//足し算で3**r
Bignum pow3(int r) {
  Bignum m = new Bignum(1);
  for(int i=0; i<r; i++) {
    m=bigadd(bigadd(m,m),m);
  }
  return m;
}

//掛け算で2**r
Bignum pow2m(int r) {
  int[] a;
  while(r>0) {
    a~=r%2;
    r/=2;
  }

  Bignum ni=new Bignum(2);
  Bignum n=new Bignum(1);

  foreach_reverse(i; a) {
    if(i) {
      n=bigmul(bigmul(n,n),ni);
//      n=bigmul(n,n); n=bigadd(n,n);
    } else {
      n=bigmul(n,n);
    }
  }
  return n;
}

// eの計算 1+1/1!+1/2!+1/3!+...+1/n!まで足して、小数点以下kケタで切捨てて表示
string e(uint n, uint k) {
  int[] bunsi, bunbo;
  bunsi=bunbo=[1];
  for(uint i=1; i<=n; i++) {
    bunsi=absadd(absmul(bunsi, toabs(i)), [1]);
    bunbo=absmul(bunbo, toabs(i));
  }
  Rational e = new Rational(1, bunsi, bunbo);
  return e.yakubun().todec(k); // 約分の効果は薄い？
}

// もう１つのeの計算 1/n!までそれぞれkケタで打ち切ったものを加える（上より精度落ちるが速い）
string e2(uint n, uint k) {
  int[] e,t;
  e=t=abspow(toabs(10), toabs(k));
  for(uint i=1; i<=n; i++) {
    t=absdiv(t, toabs(i));
    e=absadd(e, t);
  }
  string s=tos(e);
  return s[0..$-k] ~ "," ~ s[$-k..$];
}

void main() {
//  writefln(pow2(100000));
//  writefln(pow2m(100000));
//  writefln(bigsub(pow2(100000),pow2m(100000))); //0
//  writefln(bigsub(pow2(1000),pow3(631)));
//  writefln(bigdiv(pow2m(1000),pow3(500)));
  writefln(e(100,100));
  writefln(e2(100,100));
}
